/**
 * 普通装饰器
 * @param target
 */
function SimpleDecorator(target: any) {
    console.log(target);
}

@SimpleDecorator
class Actor {
    name: string = "Actor";

    say() {
        console.log("I`m Actor !");
    }
}

/**
 * 类装饰器
 * @param name
 * @returns
 */
function ClassDecorator(name: string) {
    return (constructor: Function) => {
        console.log(constructor);
    };
}

/**
 * 类装饰器(自定义扩展属性)
 * @param name
 * @returns
 * @desc 都未生效
 */
function ClassDecorator1(name: string) {
    return (constructor: Function & { name: string /*, adress: string err-没有adress属性*/ }) => {
        console.log(constructor);
        // constructor.name = name //build failed, name is ready-only, 只读属性
        constructor.prototype.name = name;
        // constructor.prototype.age = 18 //err, 使用装饰器的时候报错, 没有age属性
        constructor.prototype["age"] = 18;
        // constructor.adress = "127.0.0.1" //err, 使用装饰器的时候报错, 没有adress属性
        // constructor["adress"] = "127.0.0.1" //err, constructor不存在adress属性
        constructor.prototype["adress"] = "127.0.0.1";
        console.log(constructor);
    };
}

/**
 * 类装饰器-扩展属性
 * @param target
 * @returns
 */
function ClassDecorator2(target: any) {
    // target.name = name //err name is not defined
    // constructor.prototype.age = 18 //err, 使用装饰器的时候报错, 没有age属性
    target.prototype["age"] = 18;
    // constructor.adress = "127.0.0.1" //err, 使用装饰器的时候报错, 没有adress属性
    // constructor["adress"] = "127.0.0.1" //err, constructor不存在adress属性
    target.prototype["adress"] = "127.0.0.1";

    return target;
}

abstract class BaseActor {
    abstract say(): void;
}

/**
 * 方法装饰器
 * @param name
 * @returns
 */
function FunctionDecorator(name: string) {
    return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
        console.log(target, "-", propertyKey, "-", descriptor);
    };
}

@ClassDecorator2
class ActorA extends Actor {
    say() {
        console.log("I`m ActorA !");
        console.log(this.name);
        console.log((this as any)["age"]);
        console.log((this as any)["adress"]);
    }
}

class ActorB extends BaseActor {
    @FunctionDecorator("ActorB:say()")
    say() {
        console.log("I`m ActorB !");
    }
}

/**
 * 属性装饰器 - 监视属性变化
 * @param target
 * @param key
 */
function PropDecorator(target: any, key: string) {
    console.log("PropDecorator enter");
    const propKey = "_on" + key.charAt(0).toUpperCase() + key.slice(1) + "Change";
    target[propKey] = function (fn: (prev: any, next: any) => void) {
        let prev = this[key];
        Reflect.defineProperty(this, key, {
            set(next) {
                fn(prev, next);
                prev = next;
            },
            get() {
                return prev;
            },
        });
    };
}

class ActorData {
    @PropDecorator
    name: string = "";

    @PropDecorator
    version: number = 0;
}

/**
 * 单元测试装饰器
 */
export default function test_decorator() {
    // const a = new Actor();
    // a.say();

    // const aa = new ActorA();
    // aa.say();

    // const ab = new ActorB();
    // ab.say();

    const ad = new ActorData();
    (ad as any)["_onVersionChange"]((prev: any, next: any) => {
        console.log(`version changed ${prev} to ${next}`);
    });

    ad.version += 1;
    ad.version += 1;
}

// test_decorator()
